package net.m2technologies.open_arm.utilities.generic_object_functions;

import java.util.Comparator;

/**
 * Copyright 2005 Mark Masterson<br> <br> Licensed under the Apache License, Version 2.0 (the "License");<br> you may
 * not use this file except in compliance with the License.<br> You may obtain a copy of the License at<br> <br>
 * http://www.apache.org/licenses/LICENSE-2.0<br> <br> Unless required by applicable law or agreed to in writing,
 * software<br> distributed under the License is distributed on an "AS IS" BASIS,<br> WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied.<br> See the License for the specific language governing permissions and<br>
 * limitations under the License.<br>
 * <p/>
 * <p>Description: </p>
 *
 * @author Mark Masterson
 * @version 0.010
 */
public class GenericObjectFunctions {

    public GenericObjectFunctions() {
    }

    /**
     * Returns a String containing the name of the Class of the Object paramter, the name of the super class (if any),
     * and the names and values of all declared fields found in the Object. If passed a null as parameter, returns an
     * empty String. <br><br>If a SecurityException is caught, the method will simply print the stack trace to
     * System.out and abort. If there is a problem determining the value of any field found, the method will print "???"
     * as the value. The "|" is used as a delimiter. A "||" delimits the jump from a class to a superclass. <br> Sample
     * usage:<br> <code>public String toString() {<br> return GenericObjectFunctions.toString(this);<br> }</code><br>
     */
    public String toString(final Object object) {
        return (new ToStringWorker()).toString(object);
    }

    /**
     * Will compare the two Object parameters, to determine if they are a) instances of the same Class, or type, and b)
     * if yes, then if the values of their declared fields are all identical.  If both conditions are met, the method
     * will return "true", otherwise "false". If a SecurityException is caught, the method will simply print the stack
     * trace to System.out and abort.<br> Sample usage:<br> <code>public boolean equals(Object objectA) {<br> return
     * GenericObjectFunctions.equals(objectA, this);<br> }</code><br>
     */
    public boolean equals(final Object objectA, final Object objectB) {
        return (new EqualsWorker()).equals(objectA, objectB);
    }

    /**
     * Will compute a hash code for the Object passed as a parameter, using the same basic technique as the equals()
     * method of this class.  A hashCode() method and an equals() method for a given Object <b>must</b> be compatible;
     * that is, if two objects are equal, they must also return identical hash codes.  For that reason, the same usage
     * of the Reflection API that is utilized in this class's equals() method is used here to calculate a hash code.
     * This may be overkill for many cases -- you should carefully weigh the benefits of using this method with those of
     * rolling your own... If a SecurityException is caught, the method will simply print the stack trace to System.out
     * and abort. If there is a problem determining the value of any field found, the method will use "???" as the
     * value.<br> Sample usage:<br> <code>public int hashCode() {<br> return GenericObjectFunctions.hashCode(this);<br>
     * }</code><br>
     */
    public int hashCode(final Object objectA) {
        return (new HashCodeWorker()).hashCode(objectA);
    }

    /**
     * Returns an implementation of the java.util.Comparator interface that uses the Reflection API to determine the
     * sort order.  Specifically, the Comparator thus obtained will use this class's hashCode() method to determine the
     * sort order: if the hash code of one object is greater than the other, the one with the greater hash code will
     * come after the other object in the sort order.  By the same token, the object with the lesser hash code will come
     * before the other object in the sort order.<br> The Comparator object that one obtains from this method must then
     * be passed as an argument to the constructor of one of the sorted Collections. The instance of that Collection
     * thus obtained will use this Comparator to sort the objects -- an example of the Decorator design pattern.<br> For
     * example, to use this method with a TreeSet Collection, one would write the following:<br> <code>
     * java.util.TreeSet baum = new java.util.TreeSet(GenericObjectFunctions.getGenericComparator());<br>
     * baum.add(a2);<br> baum.add(a1);<br> </code> Assuming that a1 is intended to be before a2 in the sort order, and
     * assuming that the Reflection API generated hash-code actually produced such a sort order, then the objects should
     * be found in the TreeSet so sorted.<b> Generally, one would use this technique rather than writing a compareTo()
     * method in each of your classes.<br> <b>NOTE: This is not a very effecient, or even a very reliable method of
     * sorting your objects.  It IS very "generic", hence the method name. However, like all very generic things, it is
     * also very inefficient, and slow.  Use this method with caution, therefore.  In many cases, it will be worthwhile
     * to consider rolling your own compareTo(Object objectA) method in any class that you intend to store in a sorted
     * Collection.</b>
     */
    public Comparator getGenericComparator() {
        return new Comparator() {
            public int compare(final Object objectA, final Object objectB) {
                int result = -1;
                final int objectAHashcode = (new GenericObjectFunctions()).hashCode(objectA);
                final int objectBHashCode = (new GenericObjectFunctions()).hashCode(objectB);
                if (objectAHashcode == objectBHashCode) {
                    result = 0;
                } else if (objectAHashcode < objectBHashCode) {
                    result = -1;
                } else if (objectAHashcode > objectBHashCode) {
                    result = 1;
                }
                return result;
            }
        };
    }

}
